/*
Copyright SecureKey Technologies Inc. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package ledger

import (
	reqContext "context"
	"time"

	"git.cloud.inspur.com/ichain/ichain-sdk-go/pkg/ichain/comm"
	"git.cloud.inspur.com/ichain/ichain-sdk-go/pkg/providers/context"
	"git.cloud.inspur.com/ichain/ichain-sdk-go/pkg/providers/ichain"
	"github.com/pkg/errors"
)

const (
	minTargets = 1
	maxTargets = 1
)

type ClientOption func(*Client) error

func WithDefaultTargetFilter(filter ichain.TargetFilter) ClientOption {
	return func(rmc *Client) error {
		rmc.filter = filter
		return nil
	}
}

type RequestOption func(ctx context.Client, opts *requestOptions) error

// requestOptions 请求的参数
type requestOptions struct {
	Targets       []ichain.Inode                       // 请求的目标节点列表
	TargetFilter  ichain.TargetFilter                  // 目标节点的过滤器
	MaxTargets    int                                  // 最大的目标节点个数
	MinTargets    int                                  // 最小的目标节点个数
	Timeouts      map[ichain.TimeoutType]time.Duration // 超时时间
	ParentContext reqContext.Context                   // 父级上下文管理超时
}

func WithTargets(targets ...ichain.Inode) RequestOption {
	return func(ctx context.Client, opts *requestOptions) error {

		// Validate targets
		for _, t := range targets {
			if t == nil {
				return errors.New("target is nil")
			}
		}

		opts.Targets = targets
		return nil
	}
}

func WithTargetEndpoints(keys ...string) RequestOption {
	return func(ctx context.Client, opts *requestOptions) error {

		var targets []ichain.Inode

		for _, url := range keys {

			inodeCfg, err := comm.NetworkInodeConfig(ctx.EndpointConfig(), url)
			if err != nil {
				return err
			}

			inode, err := ctx.IChainProvider().CreateInodeFromConfig(inodeCfg)
			if err != nil {
				return errors.WithMessage(err, "creating inode from config failed")
			}

			targets = append(targets, inode)
		}

		return WithTargets(targets...)(ctx, opts)
	}
}

func WithTargetFilter(targetFilter ichain.TargetFilter) RequestOption {
	return func(ctx context.Client, opts *requestOptions) error {
		opts.TargetFilter = targetFilter
		return nil
	}
}

func WithMaxTargets(maxTargets int) RequestOption {
	return func(ctx context.Client, opts *requestOptions) error {
		opts.MaxTargets = maxTargets
		return nil
	}
}

func WithMinTargets(minTargets int) RequestOption {
	return func(ctx context.Client, opts *requestOptions) error {
		opts.MinTargets = minTargets
		return nil
	}
}

func WithTimeout(timeoutType ichain.TimeoutType, timeout time.Duration) RequestOption {
	return func(ctx context.Client, o *requestOptions) error {
		if o.Timeouts == nil {
			o.Timeouts = make(map[ichain.TimeoutType]time.Duration)
		}
		o.Timeouts[timeoutType] = timeout
		return nil
	}
}

func WithParentContext(parentContext reqContext.Context) RequestOption {
	return func(ctx context.Client, o *requestOptions) error {
		o.ParentContext = parentContext
		return nil
	}
}
